package reedSolomon;
import controleur.QRCommon;
import dataMode.QRData;


public class ReedSolomon {
	public static final int RS_PERM_ERROR = -1;
	private static final Galois galois = Galois.getInstance();
	private int npar;
	private QRData qrdata;
	private int[] data;
	private int[] encodeGx;
	private int[] parity;
	
	public ReedSolomon(QRData qrdata) {
		this.qrdata = qrdata;
		this.data = QRCommon.bitToDecimal(qrdata);
		this.npar = getNbErrorCorrectionCode();
		
		this.parity = new int[this.npar];
		
		makeEncodeGx();
		encode(data,parity);
	}

	private void  makeEncodeGx() {
		encodeGx = new int[npar];
		encodeGx[npar - 1] = 1;
		for(int kou = 0; kou < npar; kou++) {
			int ex = galois.toExp(kou);	
			for(int i = 0; i < npar - 1; i++) {
				
				encodeGx[i] = galois.mul(encodeGx[i], ex) ^ encodeGx[i + 1];
			}
			encodeGx[npar - 1] = galois.mul(encodeGx[npar - 1], ex);	
		}
	}

	public int encode(int[] data, int length, int[] parity, int parityStartPos)	{
		if(length < 0 || length + npar > 255) {
			return RS_PERM_ERROR;
		}

		int[] wr = new int[npar];

		for(int idx = 0; idx < length; idx++) {
			int code = data[idx];
			int ib = wr[0] ^ code;
			for(int i = 0; i < npar - 1; i++) {
				wr[i] = wr[i + 1] ^ galois.mul(ib, encodeGx[i]);
			}
			wr[npar - 1] = galois.mul(ib, encodeGx[npar - 1]);
		}
		if(parity != null) {
			System.arraycopy(wr, 0, parity, parityStartPos, npar);
		}
		return 0;
	}

	public int encode(int[] data, int length, int[] parity)	{
		return encode(data, length, parity, 0);
	}

	public int encode(int[] data, int[] parity)	{
		return encode(data, data.length, parity, 0);
	}

	public int[] getParity() {
		return this.parity;
	}
	
	public String getStringParity() {
		StringBuffer stringParity = new StringBuffer();
		
		for(int i=0; i<this.parity.length; i++) {
			stringParity.append(convertDecimalTo8Bits(this.parity[i]));
		}
		
		return stringParity.toString();
	}
	
	private String convertDecimalTo8Bits(int nb) {
		String bitData = Integer.toBinaryString(nb);
		bitData = addZeroOnLeft(bitData, 8);
		
		return bitData;
	}
	
	private String addZeroOnLeft(String data, int bitSize) {
		StringBuffer dataBuffer = new StringBuffer(data);
		int i, lenghtData = data.length();

		for(i = 0; i < bitSize-lenghtData; i++) {
			dataBuffer.insert(0,"0");
		}

		return dataBuffer.toString();
	}
	
	public int getNbErrorCorrectionCode() {
		return QRCommon.nbErrorCorrectionCode[this.qrdata.getVersion() - 1][this.qrdata.getErrorCorrectionLevel()-1];
	}
	
	public int getNbRSBlocks() {
		return QRCommon.nbRSBlocks[this.qrdata.getVersion() - 1][this.qrdata.getErrorCorrectionLevel()-1];
	}
}
